package com.video.main_video.controller;

import com.alibaba.fastjson.JSONObject;
import com.video.main_video.api.Api;
import com.video.main_video.api.ServiceApi;
import com.video.main_video.api.ServiceEnumApi;
import com.video.main_video.common.cutException.ResponseException;
import com.video.main_video.common.cutException.ResponseExceptionEnum;
import com.video.main_video.common.mateConfig.Meta;
import com.video.main_video.common.request.BaseRequest;
import com.video.main_video.common.response.BaseResponse;
import com.video.main_video.common.response.ZouResponseBody;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

@RestController
@RequestMapping("/api")
public class ApiController {

    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private ServiceApi serviceApi;

    @ZouResponseBody
    @PostMapping("/json")
    public Object apiJson(@RequestBody BaseRequest req) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        String filename = req.getFileName();
        String[] file = filename.split("_");
        System.out.println(Arrays.toString(file));
        System.out.println(file.length);
        if (file.length < 2) throw new ResponseException(ResponseExceptionEnum.SERVER_ARGS_ERROR, "没有对应的filename");
        if (!"wx".equals(file[0])) {
            throw new ResponseException(ResponseExceptionEnum.SERVER_ARGS_ERROR, "filename必须以wx开头");
        }
        Class<?> cmd = ServiceEnumApi.fromNameByDesc(file[1]);
        Optional.ofNullable(cmd).orElseThrow(() -> new ResponseException(ResponseExceptionEnum.SERVER_ARGS_ERROR, "枚举转换错误"));
        String reqCmd = file[1].toLowerCase(Locale.ROOT);
        String path = file[2];
        //自定义的枚举类 如SoftwareEnumApi
        Method handler = cmd.getMethod("fromNameByDesc", String.class);
        Class<?> _class = (Class<?>) handler.invoke(cmd, path);  //会返回对应的类
        Optional.ofNullable(_class).orElseThrow(() -> new ResponseException(ResponseExceptionEnum.SERVER_ARGS_ERROR, "找不到manager"));
        String jsonData = req.getBizContent();
        /**
         * 获取所有使用Cmd 注解的bean对象        *
         * */
        Map<String, Object> cmdAnnotationBeans = applicationContext.getBeansWithAnnotation(Meta.class);

        Object requestBean = getBeanClass(cmdAnnotationBeans, reqCmd, path, jsonData);

        /**
         * 获取所有使用Api 注解的bean对象        *
         * */
        Map<String, Object> apiAnnotationBeans = applicationContext.getBeansWithAnnotation(Api.class);

        return invokeHandler(apiAnnotationBeans, _class, requestBean);
    }

    /**
     * 从spring容器中查找符合接口的bean来进行使用
     */
    private Object getBeanClass(Map<String, Object> beanValue, String reqCmd, String path, String jsonData)
            throws IllegalAccessException, ResponseException, NoSuchMethodException, InvocationTargetException {
        path=path.toLowerCase(Locale.ROOT);
        Object requestBean = null;
        for (Object bean : beanValue.values()) {
            /**
             * 拿到bean上面的Cmd注解 通过注解的属性值来判断需要走那个接口
             *
             * */
            Meta c = AnnotationUtils.findAnnotation(bean.getClass(), Meta.class);
            if (null == c) continue;
            //拿到枚举对应的类
            String targetCmd = c.cmd().toString().toLowerCase(Locale.ROOT);

            /**把json转为对象 这里需要
             * 注意的是不能用新的对象去接收JSONObject.parseObject 方法的返回值
             * 否则单例池中的bean就没有数据
             *
             * */
            if (reqCmd.equals(targetCmd) && path.equals(c.path().toLowerCase(Locale.ROOT))) {
                JSONObject.parseObject(jsonData, bean.getClass());
                bean = JSONObject.parseObject(jsonData, bean.getClass());
                requestBean = bean;

                List<Field> fields = Arrays.asList(requestBean.getClass().getDeclaredFields());
                fieldIsNull(fields, bean);
                break;
            }
        }
        if (null == requestBean) throw new ResponseException(ResponseExceptionEnum.SERVER_ARGS_ERROR, "没有对应的Enum");
        return requestBean;
    }

    /**
     * 反射调用handler方法执行业务逻辑
     */
    private Object invokeHandler(Map<String, Object> apiAnnotationBeans, Class<?> cmd, Object requestBean)
            throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        for (Map.Entry<String, Object> entry : apiAnnotationBeans.entrySet()) {
            // 获取SpringBean的实例
            Class<?> targetBean = entry.getValue().getClass();
            Optional.ofNullable(targetBean).orElseThrow(() -> new ResponseException(ResponseExceptionEnum.SERVER_ARGS_ERROR, "无实例bean"));
            String className = entry.getValue().getClass().getName().split("\\$\\$")[0]; //todo
            if (cmd.getName().equals(className)) {
                return serviceApi.handler(targetBean, requestBean);
            }
        }
        BaseResponse res = new BaseResponse();
        res.setError("not found bean");
        res.setCode(1008);
        return res;
    }


    /**
     * 由于通过注解调用函数导致valid失效
     * 所以此方法是为了让字段验证起作用
     */
    private void fieldIsNull(List<Field> fields, Object bean)
            throws IllegalAccessException, ResponseException {
//        for (Field field : fields) {
//
////            Require require = field.getDeclaredAnnotation(Require.class);
//            NotNull notNull = field.getDeclaredAnnotation(NotNull.class);
////            NotEmpty notEmpty = field.getDeclaredAnnotation(NotEmpty.class);
//            /**
//             * 判断属性上有没有加上
//             * 其中的一种注解
//             *
//             * */
//            String msg = require == null ? (notEmpty == null ? (notNull == null ? null : notNull.message()) : notEmpty.message()) : require.message();
//            if (msg == null) continue;
//            field.setAccessible(true);  //打开私有属性的访问权限
//            if (field.get(bean) == null) {
//                field.setAccessible(false);//记得关闭私有属性的访问权限
//                throw new FqException(FqExceptionEnum.DATA_NOT_FOUND, msg);
//            }
//        }
    }


}
